#include <ntddk.h>

template<typename T = void>
class kunique_ptr
{
public:
	kunique_ptr(T* p = nullptr) : _p(p) {}
	
	~kunique_ptr()
	{
		Release();
	}

	kunique_ptr(const kunique_ptr&)            = delete;
	kunique_ptr& operator=(const kunique_ptr&) = delete;

	kunique_ptr(kunique_ptr&& other) : _p(other._p)
	{
		other._p = nullptr;
	}

	kunique_ptr& operator=(kunique_ptr&& other)
	{
		if (&other != this) {
			Release();
			_p = other._p;
			other._p = nullptr;
		}
		return *this;
	}

	T* operator->() const
	{
		return _p;
	}

	T& operator*() const
	{
		return *_p;
	}

private:
	T* _p;

private:
	void Release()
	{
		if (_p != nullptr) {
			ExFreePool(_p);
		}
	}
};

class MyData
{
public:
	ULONG Data1;
	HANDLE Data2;
};

VOID
DriverUnload(_In_ PDRIVER_OBJECT DriverObject);

EXTERN_C
NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegisterPath)
{
	DriverObject->DriverUnload = DriverUnload;

	kunique_ptr<MyData> Data((MyData*)ExAllocatePoolWithTag(PagedPool, sizeof(MyData), 'Ling'));

	Data->Data1 = 1042;

	KdPrint(("%u\n", Data->Data1));

	KdPrint(("Driver loaded successfully\n"));

	return STATUS_SUCCESS;
}

VOID
DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
{
	KdPrint(("Driver uninstalled successfully\n"));
}